package tool.zyk.starter;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import tool.zyk.configuration.SimpleRpcConfiguration;
import tool.zyk.protocol.ProtocolB2MDecoder;
import tool.zyk.protocol.ProtocolM2BEncoder;
import tool.zyk.protocol.ProtocolRequestM2MDecoder;
import tool.zyk.protocol.ProtocolResponseM2MEncoder;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * author: zyk
 * datetime: 2024/2/3 21:30
 * describe:
 */
@Slf4j
public class ServerStarter {
    private final SimpleRpcConfiguration simpleRpcConfiguration;

    public ServerStarter(SimpleRpcConfiguration simpleRpcConfiguration) {
        this.simpleRpcConfiguration = simpleRpcConfiguration;
    }

    private Channel serverChannel;


    public void start() {
        CompletableFuture.runAsync(() -> {
            try {
                Integer port = simpleRpcConfiguration.getServerPort();
                NioEventLoopGroup bossExecutor = new NioEventLoopGroup();
                NioEventLoopGroup workerExecutor = new NioEventLoopGroup();
                ChannelFuture channelFuture = new ServerBootstrap()
                        .group(bossExecutor, workerExecutor)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<NioSocketChannel>() {
                            @Override
                            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                                nioSocketChannel.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                                //协议解码器
                                nioSocketChannel.pipeline().addLast(new ProtocolB2MDecoder());
                                nioSocketChannel.pipeline().addLast(new ProtocolRequestM2MDecoder(simpleRpcConfiguration));
                                //协议编码器
                                nioSocketChannel.pipeline().addLast(new ProtocolM2BEncoder());
                                nioSocketChannel.pipeline().addLast(new ProtocolResponseM2MEncoder(simpleRpcConfiguration));
                            }
                        })
                        .bind(port);
                channelFuture.sync();
                Channel channel = channelFuture.channel();
                log.debug("rpc server start success,server port :{}", port);
                channel.closeFuture().addListener((ChannelFutureListener) future -> {
                    bossExecutor.shutdownGracefully();
                    workerExecutor.shutdownGracefully();
                });
                channel.closeFuture().sync();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public void close() {
        if (Objects.nonNull(serverChannel)) {
            serverChannel.close();
        }
    }
}
